package cn.zorbus.laian.infrastructure.repository;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.crypto.SecureUtil;
import cn.zorbus.laian.domain.repository.IVideoRepository;
import cn.zorbus.laian.domain.service.IVideoCaptureService;
import cn.zorbus.laian.domain.service.VideoScreenshotService;
import cn.zorbus.laian.infrastructure.bus.UdpEventBus;
import cn.zorbus.laian.infrastructure.common.command.VideoChangeCommand;
import cn.zorbus.laian.infrastructure.common.command.VideoStatusCommand;
import cn.zorbus.laian.infrastructure.common.view.VideoView;
import cn.zorbus.laian.infrastructure.config.VideoProperties;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Repository;

import java.io.File;
import java.io.FileFilter;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * create in 2023/12/4 03:04
 *
 * @author shishaodong
 * @version 0.0.1
 */
@Slf4j
@Repository
@RequiredArgsConstructor
public class VideoRepository implements IVideoRepository {

    private Map<String, VideoView> map = new LinkedHashMap<>(16);

    private static final AtomicReference<VideoView> ATOMIC_REFERENCE = new AtomicReference<>();

    private final VideoProperties properties;

//    private final IVideoCaptureService screenshotService;

    private final UdpEventBus eventBus;

    private FileFilter fileFilter;

    @PostConstruct
    public void init() {
        this.fileFilter = file -> properties.getSuffix()
                .stream()
                .anyMatch(s -> CharSequenceUtil.endWithIgnoreCase(file.getName(), s));
        run();
        this.map.values().stream().findFirst().ifPresent(ATOMIC_REFERENCE::set);
    }

    @Scheduled(fixedDelay = 1000)
    public void run() {
        this.map = FileUtil.loopFiles(properties.getPath(), fileFilter)
                .stream()
                .map(this::getVideoView)
                .collect(Collectors.toMap(VideoView::getId, x -> x));
    }

    @Override
    public VideoView findById(String id) {
        return map.getOrDefault(id, VideoView.defaultVideoView());
    }

    @Override
    public VideoView findCurrent() {
        return ATOMIC_REFERENCE.get();
    }

    @Override
    public Collection<VideoView> findAllVideos() {
        return map.values();
    }

    @Override
    public int videoChange(@NotNull VideoChangeCommand command) {
        log.info("{}", command);
        VideoView view = map.get(command.id());
        log.info("{}|{}", command, view);
        ATOMIC_REFERENCE.set(view);
        if (isVideo(view.getVideoPath())) {
            String message = "1|" + command.id() + "|" + view.getStatus() + "|" + view.getVideoPath();
            eventBus.sentEvent(message);
            log.info("videoChange :{}", message);
            return 0;
        }
        String message = "3|" + command.id() + "|1|" + view.getVideoPath();
        eventBus.sentEvent(message);
        log.info("imageChange :{}", message);
        return 0;
    }

    @Override
    public int videoStatus(VideoStatusCommand command) {
        VideoView view = ATOMIC_REFERENCE.get();
        if (Objects.isNull(view)) {
            return 1;
        }
        view.status(command);
        String message = "1|" + command.id() + "|" + view.getStatus() + "|" + view.getVideoPath();
        ATOMIC_REFERENCE.set(view);
        eventBus.sentEvent(message);
        log.info("videoStatus :{}", message);
        return 0;
    }

    @Contract("_ -> new")
    @NotNull
    private VideoView getVideoView(@NotNull File file) {
        log.debug("{}", file.getAbsolutePath());
        String absolutePath = file.getAbsolutePath();
        if (isVideo(absolutePath)) {
//            String screenshotPath = screenshotService.screenshot(absolutePath);
            return VideoView.builder()
                    .id(SecureUtil.md5(absolutePath))
                    .filename(file.getName())
//                    .coverPath(screenshotPath)
                    .videoPath(absolutePath)
                    .lastModified(new Date(file.lastModified()))
//                    .coverImage(readImage(screenshotPath))
                    .status(0)
                    .build();
        }
        return VideoView.builder()
                .id(SecureUtil.md5(absolutePath))
                .filename(file.getName())
                .videoPath(absolutePath)
                .lastModified(new Date(file.lastModified()))
//                .coverImage(readImage(absolutePath))
                .status(0)
                .build();
    }

    private boolean isVideo(String absolutePath) {
        return properties.getVideo().stream().anyMatch(s -> StringUtils.endsWithIgnoreCase(absolutePath, s));
    }

    public byte[] readImage(String screenshotPath) {
        return FileUtil.readBytes(screenshotPath);
    }
}
